package com.gla.giliair.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gla.giliair.dao.CabinInfoDao;
import com.gla.giliair.dao.FlightDao;
import com.gla.giliair.dao.SeatDao;
import com.gla.giliair.entity.*;
import com.gla.giliair.service.*;
import com.gla.giliair.util.BeanUtil;
import com.gla.giliair.util.MapGenerator;
import com.gla.giliair.web.vo.CabinInfoVO;
import com.gla.giliair.web.vo.FlightVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description:
 * @Author: Yingtian qian
 * @Date: 2021/8/24 11:03
 */
@Service
public class FlightServiceImpl implements FlightService {
    @Autowired
    private FlightDao flightDao;

    @Autowired
    private CabinInfoDao cabinInfoDao;

    @Autowired
    private SeatDao seatDao;

    @Autowired
    private CabinInfoService cabinInfoService;

    @Autowired
    private CompanyService companyService;

    @Autowired
    private PlanemodelService planemodelService;

    @Autowired
    private CompanyPlanemodelService companyPlanemodelService;

    @Autowired
    private DiscountService discountService;

    @Autowired
    private StaticSeatService staticSeatService;

    @Autowired
    private SeatService seatService;

    @Override
    public Flight selectFlightById(Long flightId) {
        if (flightId != null) {
            FlightExample flightExample = new FlightExample();
            flightExample.or().andFlightIdEqualTo(flightId).andIsDeletedEqualTo(0);
            List<Flight> flightList = flightDao.selectByExample(flightExample);
            if (flightList.isEmpty()) {
                return null;
            }
            return flightList.get(0);
        }
        return null;
    }

    @Override
    public List<Flight> selectFlightsByLeaveAndTime(String leavePoint, Date beginIn, Date endIn, FlightExample orderBy) {
        if (!"".equals(leavePoint) && beginIn != null && endIn != null) {
            orderBy.or().andLeavePointEqualTo(leavePoint).andLeaveTimeBetween(beginIn, endIn).andIsDeletedEqualTo(0);
            List<Flight> flightList = flightDao.selectByExample(orderBy);
            return flightList;
        }
        return null;
    }

    @Override
    public List<Flight> selectFlightsByLeaveAndArriveAndTime(String leavePoint, String arrivePoint, Date beginIn, Date endIn, FlightExample orderBy) {
        if (!"".equals(leavePoint) && !"".equals(arrivePoint) && beginIn != null && endIn != null) {
            orderBy.or().andLeavePointEqualTo(leavePoint).andArrivePointEqualTo(arrivePoint).andLeaveTimeBetween(beginIn, endIn).andIsDeletedEqualTo(0);
            List<Flight> flightList = flightDao.selectByExample(orderBy);
            return flightList;
        }
        return null;
    }

    @Override
    public List<Flight> selectAllFlights(FlightExample orderBy, boolean showDeleted) {
        if (!showDeleted) {
            orderBy.or().andIsDeletedEqualTo(0);
        }
        List<Flight> flightList = flightDao.selectByExample(orderBy);
        return flightList;
    }

    @Override
    public List<Flight> selectFlightsByParams(FlightExample orderBy, boolean showDeleted, FlightVO searchParams) {
        FlightExample.Criteria criteria = orderBy.createCriteria();
        if (!showDeleted) {
            criteria.andIsDeletedEqualTo(0);
        }
        if (StringUtils.hasText(searchParams.getFlightNumber())) {
            criteria.andFlightNumberLike("%" + searchParams.getFlightNumber() + "%");
        }
        if (StringUtils.hasText(searchParams.getLeavePoint())) {
            criteria.andLeavePointLike("%" + searchParams.getLeavePoint() + "%");
        }
        if (StringUtils.hasText(searchParams.getArrivePoint())) {
            criteria.andArrivePointLike("%" + searchParams.getArrivePoint() + "%");
        }
        if (StringUtils.hasText(searchParams.getLeaveAirport())) {
            criteria.andLeaveAirportLike("%" + searchParams.getLeaveAirport() + "%");
        }
        if (StringUtils.hasText(searchParams.getArriveAirport())) {
            criteria.andArriveAirportLike("%" + searchParams.getArriveAirport() + "%");
        }
        if (searchParams.getLeaveTime() != null) {
            Date beginIn = searchParams.getLeaveTime();
            Date endIn = null;
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(beginIn);
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String sDateStr = sdf.format(calendar.getTime());
            try {
                endIn = sdf.parse(sDateStr);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            criteria.andLeaveTimeBetween(beginIn, endIn);
        }
        List<Flight> flightList = flightDao.selectByExample(orderBy);
        return flightList;
    }

    @Override
    public Map<String, Object> findSpecialFlightsByLeaveAndTime(String leavePoint, Date beginIn, Date endIn, String sort, boolean isASC, Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<Flight> flightList = selectFlightsByLeaveAndTime(leavePoint, beginIn, endIn, flightSort(sort, isASC));
        PageInfo pageInfo = new PageInfo(flightList);

        if (!flightList.isEmpty()) {
            List<FlightVO> flightVOList = BeanUtil.copyList(flightList, FlightVO.class);
            //不需要cabininfo信息
            pageInfo.setList(flightVOList);
            return MapGenerator.getResWithData(200, "查询成功！", pageInfo);
        } else {
            return MapGenerator.getRes(201, "查询结果为空！");
        }
    }

    @Override
    public Map<String, Object> findFlightsInADayByLeaveAndArriveAndTime(String leavePoint, String arrivePoint, Date beginIn, String sort, boolean isASC, Integer page, Integer pageSize) {
        //根据beginIn+1天，计算endIn
        Date endIn = null;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginIn);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String sDateStr = sdf.format(calendar.getTime());
        try {
            endIn = sdf.parse(sDateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        PageHelper.startPage(page, pageSize);
        List<Flight> flightList = selectFlightsByLeaveAndArriveAndTime(leavePoint, arrivePoint, beginIn, endIn, flightSort(sort, isASC));
        PageInfo pageInfo = new PageInfo(flightList);

        if (!flightList.isEmpty()) {
            List<FlightVO> flightVOList = BeanUtil.copyList(flightList, FlightVO.class);
            for (FlightVO flightVO : flightVOList) {
                CabinInfo cabinInfo = cabinInfoService.selectCabinInfoById(flightVO.getCabinInfoId());
                CabinInfoVO cabinInfoVO = new CabinInfoVO();
                BeanUtil.copyOne(cabinInfo, cabinInfoVO);
                flightVO.setCabinInfo(cabinInfoVO);
            }
            pageInfo.setList(flightVOList);
            return MapGenerator.getResWithData(200, "查询成功！", pageInfo);
        } else {
            return MapGenerator.getRes(201, "查询结果为空！");
        }
    }

    @Override
    public Map<String, Object> findAllFlights(String sort, boolean isASC, boolean showDeleted, Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<Flight> flightList = selectAllFlights(flightSort(sort, isASC), showDeleted);
        PageInfo pageInfo = new PageInfo(flightList);
        if (!flightList.isEmpty()) {
            List<FlightVO> flightVOList = BeanUtil.copyList(flightList, FlightVO.class);
            for (FlightVO flightVO : flightVOList) {
                CabinInfo cabinInfo = cabinInfoService.selectCabinInfoById(flightVO.getCabinInfoId());
                CabinInfoVO cabinInfoVO = new CabinInfoVO();
                BeanUtil.copyOne(cabinInfo, cabinInfoVO);
                flightVO.setCabinInfo(cabinInfoVO);
            }
            pageInfo.setList(flightVOList);
            return MapGenerator.getResWithData(200, "查询航班列表成功！", pageInfo);
        } else {
            return MapGenerator.getRes(201, "查询结果为空！");
        }
    }

    @Override
    public Map<String, Object> addFlight(Flight flight, CabinInfo cabinInfo) {
        //填充航空公司冗余字段
        Long companyId = flight.getCompanyId();
        Company companyFromDB = companyService.selectCompanyById(companyId);
        if (companyFromDB == null) {
            return MapGenerator.getRes(514, "航空公司不存在！");
        }
        flight.setCompanyCode(companyFromDB.getCompanyCode());
        flight.setCompanyName(companyFromDB.getCompanyName());

        //填充飞机机型冗余字段
        Long planemodelId = flight.getPlanemodelId();
        if (companyPlanemodelService.selectCompanyPlanemodelByCompanyIdAndPlanemodelId(companyId, planemodelId) == null) {
            return MapGenerator.getRes(515, "该航空公司旗下不存在这种飞机机型！");
        }
        Planemodel planemodelFromDB = planemodelService.selectPlanemodelById(planemodelId);
        if (planemodelFromDB == null) {
            return MapGenerator.getRes(519, "原飞机机型已被删除！");
        }
        flight.setPlanemodelName(planemodelFromDB.getPlanemodelName());

        //获取折扣幅度方案
        Discount discountFromDB = discountService.selectDiscountById(cabinInfo.getDiscountId());
        if (discountFromDB == null) {
            return MapGenerator.getRes(516, "折扣幅度方案不存在！");
        }
        if (!discountFromDB.getCompanyId().equals(companyId)) {
            return MapGenerator.getRes(517, "该航空公司旗下不存在这种折扣幅度方案！");
        }

        //计算耗费时长
        long millisecond = flight.getArriveTime().getTime() - flight.getLeaveTime().getTime();
        if (millisecond <= 0) {
            return MapGenerator.getRes(518, "到达时间大于等于出发时间，数据不合法！");
        }
        long day = millisecond / (24 * 60 * 60 * 1000);
        long hour = (millisecond / (60 * 60 * 1000) - day * 24);
        long min = ((millisecond / (60 * 1000)) - day * 24 * 60 - hour * 60);
        String flightDuration = "";
        if (day > 0) {
            flightDuration = flightDuration + day + "天";
        }
        if (hour > 0) {
            flightDuration = flightDuration + hour + "小时";
        }
        if (min > 0) {
            flightDuration = flightDuration + min + "分钟";
        }
        flight.setFlightDuration(flightDuration);

        //计算最低票价
        BigDecimal first = cabinInfo.getFirstClassPrice();
        BigDecimal business = cabinInfo.getBusinessClassPrice();
        BigDecimal economy = cabinInfo.getEconomyClassPrice();
        BigDecimal leastOriginalPrice = first.min(business).min(economy);
        flight.setLeastOriginalPrice(leastOriginalPrice);
        flight.setLeastPrice(leastOriginalPrice.multiply(discountFromDB.getAdultDiscount()).multiply(discountFromDB.getNormalDiscount()));

        //拼接航班号（不做校验，请管理员谨慎决定）
        flight.setFlightNumber(flight.getCompanyCode() + flight.getFlightNumber());

        //填充创建、更新日期
        Date nowDate = new Date();
        flight.setCreateTime(nowDate);
        flight.setUpdateTime(nowDate);

        if (flightDao.insertSelective(flight) > 0) {
            //将插入后获取的主键填入其他数据项
            cabinInfo.setFlightId(flight.getFlightId());
            cabinInfo.setCreateTime(nowDate);
            cabinInfo.setUpdateTime(nowDate);
            if (cabinInfoDao.insertSelective(cabinInfo) <= 0) {
                return MapGenerator.getRes(520, "内部错误！");
            }
            //反向更新舱位信息id；若不进行反向更新，须提前预知flightId的值，仍需要三次数据库操作：先查一次航班表，获取其中最高id的值，然后再进行两次插入
            flight.setCabinInfoId(cabinInfo.getCabinInfoId());
            flight.setUpdateTime(null);
            if (flightDao.updateByPrimaryKeySelective(flight) <= 0) {
                return MapGenerator.getRes(520, "内部错误！");
            }
            //生成动态座位
            List<StaticSeat> staticSeatList = staticSeatService.selectStaticSeatsByPlanemodelId(planemodelId);
            for (StaticSeat staticSeat : staticSeatList) {
                Seat seat = new Seat();
                seat.setStaticSeatId(staticSeat.getStaticSeatId());
                seat.setSeatNumber(staticSeat.getSeatNumber());
                seat.setSeatType(staticSeat.getSeatType());
                seat.setFlightId(flight.getFlightId());
                seat.setCreateTime(nowDate);
                seat.setUpdateTime(nowDate);
                if (seatDao.insertSelective(seat) <= 0) {
                    return MapGenerator.getRes(520, "内部错误！");
                }
            }
            return MapGenerator.getRes(200, "添加航班成功！");
        }
        return MapGenerator.getRes(520, "内部错误！");
    }

    @Override
    public Map<String, Object> modifyFlight(Flight flight, CabinInfo cabinInfo) {
        Flight flightFromDB = selectFlightById(flight.getFlightId());
        if (flightFromDB == null) {
            return MapGenerator.getRes(502, "航班不存在！");
        }
        //把参数信息项中的非空字段合并到来自数据库的信息项中
        BeanUtil.copyOneIgnoreNull(flight, flightFromDB);

        //重新填充航空公司冗余字段，若无航空公司id，则不执行代码
        Long companyId = flight.getCompanyId();
        if (companyId != null) {
            Company companyFromDB = companyService.selectCompanyById(companyId);
            if (companyFromDB == null) {
                return MapGenerator.getRes(503, "航空公司不存在！");
            }
            if (companyPlanemodelService.selectCompanyPlanemodelByCompanyIdAndPlanemodelId(companyId, flightFromDB.getPlanemodelId()) == null) {
                return MapGenerator.getRes(504, "该航空公司旗下不存在这种飞机机型！");
            }
            flightFromDB.setCompanyCode(companyFromDB.getCompanyCode());
            flightFromDB.setCompanyName(companyFromDB.getCompanyName());
        }

        //禁止修改飞机机型id，否则会影响动态座位表

        //重新获取折扣幅度方案，并校验折扣方式是否存在，若无折扣幅度id，则不执行代码
        Long discountId = cabinInfo.getDiscountId();
        Discount discountFromDB = null;
        if (discountId != null) {
            discountFromDB = discountService.selectDiscountById(discountId);
            if (discountFromDB == null) {
                return MapGenerator.getRes(505, "折扣幅度方案不存在！");
            }
            if (!discountFromDB.getCompanyId().equals(companyId)) {
                return MapGenerator.getRes(506, "该航空公司旗下不存在这种折扣幅度方案！");
            }
        }

        //重新计算耗费时长，若到达时间、出发时间均为空，则不执行代码
        if (flight.getLeaveTime() != null || flight.getArriveTime() != null) {
            long millisecond = flightFromDB.getArriveTime().getTime() - flightFromDB.getLeaveTime().getTime();
            if (millisecond <= 0) {
                return MapGenerator.getRes(507, "到达时间大于等于出发时间，数据不合法！");
            }
            long day = millisecond / (24 * 60 * 60 * 1000);
            long hour = (millisecond / (60 * 60 * 1000) - day * 24);
            long min = ((millisecond / (60 * 1000)) - day * 24 * 60 - hour * 60);
            String flightDuration = "";
            if (day > 0) {
                flightDuration = flightDuration + day + "天";
            }
            if (hour > 0) {
                flightDuration = flightDuration + hour + "小时";
            }
            if (min > 0) {
                flightDuration = flightDuration + min + "分钟";
            }
            flightFromDB.setFlightDuration(flightDuration);
        }

        //重新计算最低票价，若三种票价均为空，则不执行代码
        CabinInfo cabinInfoFromDB = cabinInfoService.selectCabinInfoById(flightFromDB.getCabinInfoId());
        if (cabinInfo.getFirstClassPrice() != null || cabinInfo.getBusinessClassPrice() != null || cabinInfo.getEconomyClassPrice() != null) {
            BeanUtil.copyOneIgnoreNull(cabinInfo, cabinInfoFromDB);
            //如果折扣方案没有更新，则把原来的折扣方案取出
            if (discountFromDB == null) {
                discountFromDB = discountService.selectDiscountById(cabinInfoFromDB.getDiscountId());
            }
            BigDecimal first = cabinInfoFromDB.getFirstClassPrice();
            BigDecimal business = cabinInfoFromDB.getBusinessClassPrice();
            BigDecimal economy = cabinInfoFromDB.getEconomyClassPrice();
            BigDecimal leastOriginalPrice = first.min(business).min(economy);
            flightFromDB.setLeastOriginalPrice(leastOriginalPrice);
            flightFromDB.setLeastPrice(leastOriginalPrice.multiply(discountFromDB.getAdultDiscount()).multiply(discountFromDB.getNormalDiscount()));
        }

        //重新拼接航班号，若无航班号非公司部分，则不执行代码
        if (StringUtils.hasText(flight.getFlightNumber())) {
            flightFromDB.setFlightNumber(flightFromDB.getCompanyCode() + flightFromDB.getFlightNumber());
        }

        //覆盖更新日期
        flightFromDB.setUpdateTime(null);

        if (flightDao.updateByPrimaryKeySelective(flightFromDB) > 0) {
            cabinInfoFromDB.setUpdateTime(null);
            if (cabinInfoDao.updateByPrimaryKeySelective(cabinInfoFromDB) <= 0) {
                return MapGenerator.getRes(520, "内部错误！");
            }
            return MapGenerator.getRes(200, "修改航班信息成功！");
        }
        return MapGenerator.getRes(520, "内部错误！");
    }

    @Override
    public Map<String, Object> deleteFlight(Long flightId, boolean isSeatDeleted) {
        Flight flightFromDB = selectFlightById(flightId);
        if (flightFromDB == null) {
            return MapGenerator.getRes(501, "航班不存在！");
        }
        flightFromDB.setIsDeleted(1);
        flightFromDB.setUpdateTime(null);
        if (flightDao.updateByPrimaryKeySelective(flightFromDB) > 0) {
            CabinInfo cabinInfo = new CabinInfo();
            cabinInfo.setCabinInfoId(flightFromDB.getCabinInfoId());
            cabinInfo.setIsDeleted(1);
            if (cabinInfoDao.updateByPrimaryKeySelective(cabinInfo) <= 0) {
                return MapGenerator.getRes(520, "内部错误！");
            }
            if (isSeatDeleted) {
                List<Seat> seatList = seatService.selectSeatsByFlightId(flightId);
                for (Seat seat : seatList) {
                    if (seatDao.deleteByPrimaryKey(seat.getSeatId()) <= 0) {
                        return MapGenerator.getRes(520, "内部错误！");
                    }
                }
            }
            return MapGenerator.getRes(200, "删除航班成功！");
        }
        return MapGenerator.getRes(520, "内部错误！");
    }

    @Override
    public Map<String, Object> searchFlights(String sort, boolean isASC, boolean showDeleted, Integer page, Integer pageSize, FlightVO searchParams) {
        if (searchParams == null) {
            return MapGenerator.getRes(500, "搜索参数为空！");
        }
        PageHelper.startPage(page, pageSize);
        List<Flight> flightList = selectFlightsByParams(flightSort(sort, isASC), showDeleted, searchParams);
        PageInfo pageInfo = new PageInfo(flightList);
        if (!flightList.isEmpty()) {
            List<FlightVO> flightVOList = BeanUtil.copyList(flightList, FlightVO.class);
            for (FlightVO flightVO : flightVOList) {
                CabinInfo cabinInfo = cabinInfoService.selectCabinInfoById(flightVO.getCabinInfoId());
                CabinInfoVO cabinInfoVO = new CabinInfoVO();
                BeanUtil.copyOne(cabinInfo, cabinInfoVO);
                flightVO.setCabinInfo(cabinInfoVO);
            }
            pageInfo.setList(flightVOList);
            return MapGenerator.getResWithData(200, "查询航班列表成功！", pageInfo);
        } else {
            return MapGenerator.getRes(201, "查询结果为空！");
        }
    }

    //排序参数转化
    private FlightExample flightSort(String sort, boolean isASC) {
        FlightExample flightExample = new FlightExample();
        sort = sort == null ? "" : sort;
        String column = "";
        String order = "desc";
        if (isASC) {
            order = "asc";
        }
        switch (sort) {
            case "flightId":
                column = "flight_id";
                break;
            case "flightNumber":
                column = "flight_number";
                break;
            case "leavePoint":
                column = "leave_point";
                break;
            case "arrivePoint":
                column = "arrive_point";
                break;
            case "leaveAirport":
                column = "leave_airport";
                break;
            case "arriveAirport":
                column = "arrive_airport";
                break;
            case "leaveTime":
                column = "leave_time";
                break;
            case "arriveTime":
                column = "arrive_time";
                break;
            case "flightDuration":
                column = "flight_duration";
                break;
            case "companyId":
                column = "company_id";
                break;
            case "companyCode":
                column = "company_code";
                break;
            case "companyName":
                column = "company_name";
                break;
            case "planemodelId":
                column = "planemodel_id";
                break;
            case "planemodelName":
                column = "planemodel_name";
                break;
            case "cabinInfoId":
                column = "cabin_info_id";
                break;
            case "leastOriginalPrice":
                column = "least_original_price";
                break;
            case "leastPrice":
                column = "least_price";
                break;
            case "createTime":
                column = "create_time";
                break;
            case "updateTime":
                column = "update_time";
                break;
            case "isDeleted":
                column = "is_deleted";
                break;
            default:
        }
        if ("".equals(column)) {
            flightExample.setOrderByClause("flight_id desc");
        } else {
            if ("flight_id".equals(column)) {
                flightExample.setOrderByClause(String.format("%s %s", column, order));
            } else {
                flightExample.setOrderByClause(String.format("%s %s , flight_id desc", column, order));
            }
        }
        return flightExample;
    }
}
